package com.infonova.product.jtf.blame.web;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.List;
import java.util.Map;

import junit.framework.Test;
import junit.framework.TestFailure;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;

import com.infonova.product.jtf.blame.ClassFinder;
import com.infonova.product.jtf.blame.dto.Call;
import com.infonova.product.jtf.blame.dto.CallGraph;
import com.infonova.product.jtf.blame.svn.Change;
import com.infonova.product.jtf.blame.util.JtfBlameUtil;


public class GraphRenderer {

    private static final String overviewFileName = "overview.html";

    private File target;

    public GraphRenderer(File target) throws IOException {
        if (!target.exists()) {
            target.mkdirs();
        };
        this.target = target;
        prepareWebResources("callgraph.js");
    }

    private void prepareWebResources(String resourceName) throws IOException {
        File file = new File(ClassFinder.getInstance().findDeep(new File(".."), resourceName));
        if (!file.getParent().equals(target)) {
            IOUtils.copy(new FileInputStream(file), new FileOutputStream(new File(target, resourceName)));
        }

        // IOUtils.copy(getClass().getResourceAsStream(resourceName), new FileWriter(new File(target, resourceName)));
    }

    public void createOverviewPage(List<TestFailure> tests) throws IOException {
        File overviewFile = new File(target, overviewFileName);
        overviewFile.createNewFile();
        OutputStreamWriter out = new FileWriter(overviewFile);
        println(out, "<!DOCTYPE HTML>");
        println(out, "<html>");
        println(out, "<body>");
        println(out, "<h1>Failed Tests</h1>");
        println(out, "<table>");
        for (TestFailure test : tests) {
            println(out, "<tr><td>");
            out.append("<a href=\"" + createHtmlName(test.failedTest()) + "\">");
            out.append(test.failedTest().toString());
            out.append("</a>");
            println(out, "</td>");
            out.append("<td>").append(test.exceptionMessage()).append("</td>");
            println(out, "</td></tr>");
        }
        out.append("</table>");
        out.append("</body>");
        out.append("</html>");
        out.flush();
    }

    private String createHtmlName(Test test) {
        return test.toString() + ".html";
    }

    public void createCallGraph(CallGraph callGraph, Map<String, List<Change>> changedFiles) throws IOException {
        File file = new File(target, createHtmlName(callGraph.getMethod()));
        file.createNewFile();
        OutputStreamWriter out = new FileWriter(file);
        println(out, "<!DOCTYPE HTML>");
        println(out, "<head>");
        println(out, "<script type=\"text/javascript\" src=\"callgraph.js\"></script>");
        println(out, "<script>");
        println(out, "draw = function(context){");
        println(out, "context.myMoveTo(10, 10);");

        println(
            out,
            "aHeader("
                + str(shortenClassName(callGraph.getMethod().getTestClazz()), callGraph.getMethod().getTestMethod())
                + ")");

        for (Call call : callGraph.getCalls()) {
            println(out,
                "aCall(" + str("" + call.getLevel(), shortenClassName(call.getClazzName()), call.getMethodName()) + ")");

            String key = JtfBlameUtil.toPartPath(call.getClazzName());
            if (changedFiles.containsKey(key)) {
                int i = 0;
                for (Change changedFile : changedFiles.get(key)) {
                    println(
                        out,
                        "aChangedFile("
                            + str("" + (i++), shortenPath(changedFile.getPartFilePath()), changedFile.getCommit()
                                .getAuthor(), changedFile.getCommit().getLog()) + ")");
                }
            }
        }

        println(out, "}");
        println(out, "</script>");
        println(out, "</head>");
        println(out, "<body>");
        println(out, "<a href=" + str(overviewFileName) + ">");
        println(out, "Back");
        println(out, "</a><br />");
        println(out,
            "<canvas id=\"canvas\" height=\"600\" width=\"1000\">Your Browser does not support html 5 canvas.</canvas>");
        println(out, "</body>");
        out.flush();
    }

    private String str(String... strings) {
        for (int i = 0; i < strings.length; i++) {
            strings[i] = "\"" + strings[i] + "\"";
        }
        return StringUtils.join(strings, ",");
    }

    private void println(OutputStreamWriter out, String string) throws IOException {
        out.append(string).append("\n");
    }

    private String shortenPath(String path) {
        int srcPathIndex = path.indexOf("/src/");
        path = path.replace("src/main/java", "...");
        path = path.replace("src/test/resources", "...");
        path = path.replace("src/main/java", "...");
        path = path.replace("src/test/resources", "...");
        if (srcPathIndex > 0) {
            String className = path.substring(srcPathIndex);
            String parts[] = className.split("/");
            for (int i = 0; i < parts.length - 2; i++) {
                parts[i] = parts[i].substring(0, Math.min(3, parts[i].length()));
            }
            className = StringUtils.join(parts, "/");
            return path.substring(0, srcPathIndex) + className;
        }
        return path;
    }

    private String shortenClassName(String className) {
        String parts[] = className.split("\\.");
        for (int i = 0; i < parts.length - 2; i++) {
            parts[i] = parts[i].substring(0, Math.min(3, parts[i].length()));
        }
        return StringUtils.join(parts, ".");
    }
}
